home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
United Public Domain Gold 2
/
United Public Domain Gold 2.iso
/
utilities
/
pu291.dms
/
pu291.adf
/
Clocks
/
SPClock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-03
|
16KB
|
562 lines
/*----------------------------------------------------------------------
SPClock
Version 2.1
A simple sprite based clock that will stay in the upper left corner
no matter which screen you switch to or where your screen scrolls
(in WB2.0).
Copyright (C) 1991, Mark Waggoner
Permission is granted to distribute this as long as no charge beyond a
reasonable media charge is required. Reasonable shall be defined to
be the amount that Fred Fish charges or last charged for a disk of
software.
You will probably want tabs set to 4 when editing this file
Compiles with Manx C, 5.2a
Note that this program uses special startup code found in start.a68
------------------------------------------------------------------------*/
#include <functions.h>
#include <string.h>
#include <stdlib.h>
#include <graphics/gfxbase.h>
#include <graphics/view.h>
#include <graphics/sprite.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/ports.h>
#include <exec/tasks.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#ifndef SUPERHIRES
#define SUPERHIRES 0x0020
#endif
/* The sprite height */
#define SPHEIGHT 10
/* Library Base Pointers */
void *SysBase = NULL;
struct GfxBase *GfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
void *DOSBase = NULL;
void *IconBase = NULL;
/* start.a68 saves the original stack pointer in _savsp */
long _savsp;
/* The workbench startup message */
struct WBStartup *WBenchMsg = NULL;
/* Option keywords */
static char KWcolor1a[] = "COLOR1";
static char KWcolor1b[] = "COLOR";
static char KWcolor2a[] = "COLOR2";
static char KWcolor2b[] = "SHADOW";
static char KWcolor3a[] = "COLOR3";
static char KWleft[] = "LEFT";
static char KWtop[] = "TOP";
static char KW24Hour[] = "24HOUR";
static char KWNoBlink[] = "NOBLINK";
static char KWQuit[] = "QUIT";
static char KWStart[] = "START";
/* a smaller (but probably slower) isspace than aztec's */
#define isspace(c) (c == ' ' || c == '\t' | c == '\n')
/* The colors to use */
static long color1[3] = {15, 0, 0};
static long color2[3] = { 0, 0, 0};
static long color3[3] = { 0,15, 0};
/* The clock position */
static long ClockX = -1,
ClockY = -1;
/* Switch options: */
static UBYTE Hours24 = 0;
static UBYTE Blink = 1;
static UBYTE StartOnly = 0;
/* The images are stored here */
static UWORD hourimage[SPHEIGHT+2][2];
static UWORD minuteimage[SPHEIGHT+2][2];
/* This data was generated from the "nums" file using nums2c.rexx
The nums are copied into the images as appropriate */
static UBYTE nums[13][2][10] = {
{ {0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00},
{0x00,0x1C,0x84,0x84,0x84,0x84,0x84,0x84,0xC0,0x7C} }, /* 0 */
{ {0x0C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x00},
{0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x18} }, /* 1 */
{ {0x3E,0x63,0x03,0x03,0x0C,0x30,0x60,0x60,0x7F,0x00},
{0x00,0x1C,0xC4,0x04,0x02,0x08,0x00,0x80,0x80,0xFE} }, /* 2 */
{ {0x3E,0x63,0x03,0x03,0x0E,0x03,0x03,0x63,0x3E,0x00},
{0x00,0x1C,0xC4,0x04,0x00,0x1C,0x04,0x04,0xC0,0x7C} }, /* 3 */
{ {0x06,0x0E,0x16,0x26,0x46,0x7F,0x06,0x06,0x06,0x00},
{0x00,0x00,0x08,0x08,0x08,0x80,0xF8,0x08,0x08,0x0C} }, /* 4 */
{ {0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x3E,0x00},
{0x00,0x9E,0x80,0x80,0x80,0xFC,0x04,0x04,0xC0,0x7C} }, /* 5 */
{ {0x3E,0x63,0x60,0x60,0x7E,0x63,0x63,0x63,0x3E,0x00},
{0x00,0x1C,0x86,0x80,0x80,0x9C,0x84,0x84,0x40,0x7C} }, /* 6 */
{ {0x7F,0x03,0x03,0x06,0x0C,0x18,0x18,0x18,0x18,0x00},
{0x00,0xFC,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x30} }, /* 7 */
{ {0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x3E,0x00},
{0x00,0x1C,0x84,0x84,0xC0,0x1C,0x84,0x84,0xC0,0x7C} }, /* 8 */
{ {0x3E,0x63,0x63,0x63,0x3F,0x03,0x03,0x63,0x3E,0x00},
{0x00,0x1C,0x84,0x84,0xC0,0x7C,0x04,0x84,0xC0,0x7C} }, /* 9 */
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, /* space */
{ {0x06,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x00},
{0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x0C} }, /* small 1 */
{ {0x06,0x09,0x01,0x01,0x02,0x04,0x08,0x08,0x0F,0x00},
{0x00,0x06,0x1A,0x02,0x00,0x00,0x00,0x10,0x10,0x1E} }, /* small 2 */
};
/* Message port and name used to indicate we are running */
struct MsgPort *SPPort = NULL;
static char portname[] = "SPClock";
/* The sprites that we allocate */
UWORD minute_spnum = -1,hour_spnum = -1;
struct SimpleSprite hour_sprite,minute_sprite;
/*-------------------------------------------------------------------
Exit the program, freeing up global resources
-------------------------------------------------------------------*/
void
exit(int code)
{
long ret = code;
if (minute_spnum != -1)
FreeSprite(minute_spnum);
if (hour_spnum != -1)
FreeSprite(hour_spnum);
if (SPPort)
DeletePort(SPPort);
if (GfxBase)
CloseLibrary((struct Library *) GfxBase);
if (IntuitionBase)
CloseLibrary((struct Library *) IntuitionBase);
if (DOSBase)
CloseLibrary((struct Library *) DOSBase);
if (WBenchMsg) {
Forbid();
ReplyMsg((struct Message *)WBenchMsg);
}
/* Get the original stack pointer back and return */
{
#asm
move.l %%ret,d0 ;pick up return exit code
move.l __savsp#,sp ;get back original stack pointer
rts ;and exit
#endasm
}
}
/*-------------------------------------------------------------------
See if SPClock is already running and signal it to stop
-------------------------------------------------------------------*/
void
KillIfRunning(void) {
struct MsgPort *oldport;
/* Check if we are already running */
Forbid();
if (oldport = FindPort(portname))
Signal(oldport->mp_SigTask,SIGBREAKF_CTRL_C);
Permit();
return;
}
/*-------------------------------------------------------------------
See if we are already running by looking for a message port
named "SPClock". If so, signal that process to stop.
If we signal another process to stop or can't open the message
port, we return an error code and the main program exits.
-------------------------------------------------------------------*/
int
CheckIfRunning(void) {
struct MsgPort *oldport;
int error = 1;
/* Check if we are already running */
Forbid();
if (oldport = FindPort(portname)) {
if (!StartOnly)
Signal(oldport->mp_SigTask,SIGBREAKF_CTRL_C);
}
else /* port doesn't exist, so add it and continue */
if (SPPort = CreatePort(portname,0)) error = 0;
Permit();
return(error);
}
/*-------------------------------------------------------------------
Open the libraries that we will be using
-------------------------------------------------------------------*/
int
OpenLibraries(void) {
register int error = 1;
/* Open up the libraries we need (look at all those evil gotos!) */
if (
((DOSBase = OpenLibrary("dos.library",0L)) != NULL) &&
((IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",0L)) != NULL) &&
((GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library",0L)) != NULL)
)
error = 0;
return(error);
}
/*-------------------------------------------------------------------
Set the colors of the currently active viewport.
This may make a mess of some screens.
If so, and it bothers you, find a better algorithm
-------------------------------------------------------------------*/
void
SetSpriteColors(void) {
int color_reg1,color_reg2;
struct ViewPort *vp;
WORD vp_max_pen;
/* base color register numbers */
color_reg1 = ((hour_spnum & 0x06)*2)+16;
color_reg2 = ((minute_spnum & 0x06)*2)+16;
vp = GfxBase->ActiView->ViewPort;
vp_max_pen = 1 << vp->RasInfo->BitMap->Depth;
if ((color_reg1 > 16) && (color_reg1 > vp_max_pen)) {
SetRGB4(vp,color_reg1+1,color1[0],color1[1],color1[2]);
SetRGB4(vp,color_reg1+2,color2[0],color2[1],color2[2]);
SetRGB4(vp,color_reg1+3,color3[0],color3[1],color3[2]);
}
if ((color_reg2 != color_reg1) && (color_reg2 > vp_max_pen)) {
SetRGB4(vp,color_reg2+1,color1[0],color1[1],color1[2]);
SetRGB4(vp,color_reg2+2,color2[0],color2[1],color2[2]);
SetRGB4(vp,color_reg2+3,color3[0],color3[1],color3[2]);
}
}
/*-------------------------------------------------------------------
Initialize the sprites
-------------------------------------------------------------------*/
int
InitSprites(void) {
int i;
/* Clear the sprite images */
for(i=0;i<SPHEIGHT+2;i++)
hourimage[i][0] = hourimage[i][1] =
minuteimage[i][0] = minuteimage[i][1] = 0;
/* Try to get sprites 2 and 3, otherwise, take whatever is available */
hour_spnum = GetSprite(&hour_sprite,2L);
if (hour_spnum == -1) {
hour_spnum = GetSprite(&hour_sprite,-1L);
if (hour_spnum == -1)
return(1);
}
minute_spnum = GetSprite(&minute_sprite,3L);
if (minute_spnum == -1) {
minute_spnum = GetSprite(&minute_sprite,-1L);
if (minute_spnum == -1)
return(1);
}
SetSpriteColors();
return(0);
}
/*-------------------------------------------------------------------
Skip past the next space delimited token in a string
-------------------------------------------------------------------*/
char *
SkipToken(char *s) {
while(*s && isspace(*s)) s++;
while(*s && !isspace(*s)) s++;
return(s);
}
/*-------------------------------------------------------------------
Check an option name for CLI parsing
-------------------------------------------------------------------*/
char *
CheckOption(char *s,char *opt) {
int l,m;
char *t;
l = strlen(opt);
/* Find the length of the next word */
m = 0; t = s;
while(*t && !isspace(*t) && *t != '=') { t++; m++; }
if (m!=l)
s = NULL;
else
if (strncmp(s,opt,l))
s = NULL;
else {
s+=l;
/* Skip past an equal sign */
while(*s && isspace(*s)) s++;
if (*s == '=') s++;
}
return(s);
}
/*-------------------------------------------------------------------
Extract a color specification from an argument
-------------------------------------------------------------------*/
char *
ExtractColor(char *s,long color[3]) {
color[0]=atoi(s);
s = SkipToken(s);
color[1]=atoi(s);
s = SkipToken(s);
color[2]=atoi(s);
s = SkipToken(s);
return(s);
}
/*-------------------------------------------------------------------
Parse workbench options
-------------------------------------------------------------------*/
void
wb_parse(struct WBStartup *wbm)
{
char *tool;
struct DiskObject *dob;
CurrentDir(wbm->sm_ArgList->wa_Lock);
if ((IconBase = OpenLibrary("icon.library", 0L)) == 0)
return;
if ((dob = GetDiskObject(wbm->sm_ArgList->wa_Name)) == 0)
goto NoDiskObj;
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor1a))
ExtractColor(tool,color1);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor1b))
ExtractColor(tool,color1);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor2a))
ExtractColor(tool,color2);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor2b))
ExtractColor(tool,color2);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor3a))
ExtractColor(tool,color3);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWtop))
ClockY = atoi(tool);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWleft))
ClockX = atoi(tool);
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KW24Hour))
Hours24 = 1;
if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWNoBlink))
Blink = 0;
FreeDiskObject(dob);
NoDiskObj:
CloseLibrary(IconBase);
IconBase = NULL;
}
/*-------------------------------------------------------------------
I parse the cli parameters before they get to main()
-------------------------------------------------------------------*/
void
cli_parse(long alen, register char *aptr)
{
char *s,*t;
s = aptr;
while(*s) {
while(*s && isspace(*s)) s++;
if ((t = CheckOption(s,KWcolor1a)) || (t = CheckOption(s,KWcolor1b)))
s = ExtractColor(t,color1);
else
if ((t = CheckOption(s,KWcolor2a)) || (t = CheckOption(s,KWcolor2b)))
s = ExtractColor(t,color2);
else
if ((t = CheckOption(s,KWcolor3a)))
s = ExtractColor(t,color3);
else
if (t = CheckOption(s,KWtop)) {
ClockY = atoi(t);
s = SkipToken(t);
}
else
if (t = CheckOption(s,KWleft)) {
ClockX = atoi(t);
s = SkipToken(t);
}
else
if (t = CheckOption(s,KW24Hour)) {
Hours24 = 1;
s = t;
}
else
if (t = CheckOption(s,KWNoBlink)) {
Blink = 0;
s = t;
}
else
if (t = CheckOption(s,KWQuit)) {
KillIfRunning();
s = t;
exit(0);
}
else
if (t = CheckOption(s,KWStart)) {
StartOnly = 1;
s = t;
exit(0);
}
else
s = SkipToken(s);
}
}
/*-------------------------------------------------------------------
Here it is!! The main program! Note that this is NOT called
like a normal C main(). This is more like the _main() routine.
You may not use any unix style standard i/o, or malloc, or
any floating point in this program!
-------------------------------------------------------------------*/
main(long alen,char *aptr) {
register struct Process *pr;
int i,o1,o2,o3,o4;
UWORD maxx;
ULONG sec,usec,lastsec = 0;
UWORD hours,minutes,pm;
ULONG line;
if (OpenLibraries()) exit(103); /* Open up the libraries */
/* Figure out if we came from workbench or a CLI and process the
arguments accordingly */
pr = (struct Process *)FindTask(0L);
if (pr->pr_CLI)
cli_parse(alen, aptr);
else {
WaitPort(&pr->pr_MsgPort);
WBenchMsg = (struct WBStartup *)GetMsg(&pr->pr_MsgPort);
if (WBenchMsg->sm_ArgList)
wb_parse(WBenchMsg);
}
/* See if we are already running, kill other process and exit if so */
if (CheckIfRunning())
exit(0);
/* Initialize the sprites. Exit if unable to do so */
if (InitSprites())
exit(105);
/* If no position specified, position the sprite near the right
side, but not so it overlaps the usual screen gadgets */
/* Can you suggest a better way to do this? */
maxx = GfxBase->ActiView->ViewPort->DWidth;
if (GfxBase->ActiView->ViewPort->Modes & HIRES) maxx *= 2;
if (ClockX < 0) ClockX = maxx - 48;
if (ClockY < 0) ClockY = 0;
hour_sprite.x = ClockX;
hour_sprite.y = ClockY;
hour_sprite.height = SPHEIGHT;
minute_sprite.x = ClockX+16;
if (GfxBase->ActiView->Modes & SUPERHIRES)
minute_sprite.x = ClockX+8;
minute_sprite.y = ClockY;
minute_sprite.height = SPHEIGHT;
/* Keep running until we get a BREAK signal */
while (!(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)) {
/* Find out what time it is */
CurrentTime(&sec,&usec);
sec = sec/60; /* sec is now minutes */
if (sec != lastsec) { /* Only update if the time has changed */
/* Calculate the hours and minutes. I keep 12 hour time! */
lastsec = sec;
minutes = sec % 60;
sec = sec/60;
hours = sec%24;
pm = 0;
if (hours*60+minutes > 720) pm = 1;
if (!Hours24) {
if (hours > 12) hours -= 12;
if (hours == 0) hours = 12;
}
o1 = hours/10+10;
if (o1 > 12) o1 = 10;
o2 = hours%10;
o3 = minutes/10;
o4 = minutes%10;
for(i=0;i<SPHEIGHT;i++) {
line = (((USHORT) nums[o1][0][i]) << 27) |
(((USHORT) nums[o2][0][i]) << 19) |
(((USHORT) nums[o3][0][i]) << 9) |
(((USHORT) nums[o4][0][i]) << 1);
hourimage[i+1][0] = (line & 0xFFFF0000) >> 16;
minuteimage[i+1][0] = (line & 0x0000FFFF);
line = (((USHORT) nums[o1][1][i]) << 27) |
(((USHORT) nums[o2][1][i]) << 19) |
(((USHORT) nums[o3][1][i]) << 9) |
(((USHORT) nums[o4][1][i]) << 1);
hourimage[i+1][1] = (line & 0xFFFF0000) >> 16;
minuteimage[i+1][1] = (line & 0x0000FFFF);
}
/* Make the Colon and AM/PM indicator */
hourimage[3][0] |= 0x0002;
hourimage[7][0] |= 0x0002;
hourimage[4][1] |= 0x0004;
hourimage[8][1] |= 0x0004;
if (pm && !Hours24) {
hourimage[5][0] |= 0x0002;
hourimage[5][1] |= 0x0002;
hourimage[6][1] |= 0x0004;
}
}
/* Make the blinking dots */
if (Blink) {
hourimage[3][0] ^= 0x0002;
hourimage[7][0] ^= 0x0002;
hourimage[4][1] ^= 0x0004;
hourimage[8][1] ^= 0x0004;
}
/* Make sure this viewport has my colors set. I would like
to not do this every time, but I'm not sure how to check
if another screen has moved to the front */
SetSpriteColors();
/* Update the image */
ChangeSprite(NULL,&hour_sprite,(PLANEPTR) hourimage);
ChangeSprite(NULL,&minute_sprite,(PLANEPTR) minuteimage);
/* Wait for 1 second */
Delay(50);
}
exit(0);
}